﻿using System;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using Helper.FileUpload;

namespace Helper.FileUpload
{
    /// <summary>
    /// 파일 업로드 도우미 클래스
    /// </summary>
    public class FileUploadHelper : Exception
    {

        #region /// 지역 변수

        private static HttpResponse Response = HttpContext.Current.Response;
        private static HttpRequest Request = HttpContext.Current.Request;
        private static HttpServerUtility Server = HttpContext.Current.Server;

        private HttpPostedFile _PostedFile;
        private string _URL;
        private string _FileName;
        private string _LastSavedFileName;
        private string _FileExtName;
        private string _FilePrefix;
        private int _FileSize;
        private string _SavedPathName;
        private string _RestrictExtention;
        private int _LimitFileSize;
        private FileUploadInfo _FileServer;
        private bool _AutoRename;
        private string _VirtualPath;
        private bool _Overwrite;
        private string _NewFileName;
        private string _PhysicalPath;
        private int _ImageWidth, _ImageHeight;
        private string _MimeType;

        #endregion

        #region /// 속성 정의

        /// <summary>
        /// 클라이언트에서 업로드한 개별 파일을 액세스할 수 있도록 설정합니다.
        /// </summary>
        public HttpPostedFile PostedFile
        {
            set
            {
                _PostedFile = value;
                _MimeType = _PostedFile.ContentType;
            }
        }

        /// <summary>
        /// 저장된 파일의 URL을 가져옵니다.
        /// </summary>
        public string URL
        {
            get { return _URL; }
        }
        /// <summary>
        /// 파일을 저장할 가상 경로명을 가져오거나 설정합니다.
        /// </summary>
        public string VirtualSavePath
        {
            get { return _VirtualPath; }
            set { _VirtualPath = value; }
        }
        /// <summary>
        /// 클라이언트 파일의 정규화된 이름을 가져옵니다.
        /// </summary>
        public string FileName
        {
            get { return _FileName; }
        }
        /// <summary>
        /// 파일명 앞에 붙일 접두사를 가져오거나 설정합니다.
        /// </summary>
        public string FilePrefix
        {
            set { _FilePrefix = value; }
            get { return _FilePrefix; }
        }
        /// <summary>
        /// 확장자를 포함한 파일명을 반환합니다.
        /// </summary>
        public string LastSavedFileName
        {
            get { return _LastSavedFileName; }
        }
        /// <summary>
        ///  업로드된 파일의 .을 포함한 확장자명을 가져옵니다.
        /// </summary>
        public string FileExtName
        {
            get { return _FileExtName; }
        }
        /// <summary>
        /// 업로드된 파일의 파일사이즈를 가져옵니다..
        /// </summary>
        public int FileSize
        {
            get { return _FileSize; }
        }
        /// <summary>
        /// 업로드된 파일의 경로명을 포함한 파일명을 가져옵니다.
        /// </summary>
        public string SavedPathName
        {
            get { return _SavedPathName; }
        }
        /// <summary>
        /// 업로드 확장자를 제한하는 정규식 문자열을 가져오거나 설정합니다.
        /// </summary>
        public string RestrictExtention
        {
            get { return _RestrictExtention; }
            set { _RestrictExtention = value; }
        }
        /// <summary>
        /// 파일 용량 제한을 설정하거나 가져옵니다.
        /// </summary>
        public int LimitFileSize
        {
            set { _LimitFileSize = value; }
            get { return _LimitFileSize; }
        }
        /// <summary>
        /// 저장할 파일 서버 정보를 설정하거나 가져옵니다.
        /// </summary>
        public FileUploadInfo FileServer
        {
            set { _FileServer = value; }
            get { return _FileServer; }
        }
        /// <summary>
        /// 파일 존재시 덮어쓰기 여부를 설정하거나 가져옵니다. 기본값 = false
        /// </summary>
        public bool Overwrite
        {
            get { return _Overwrite; }
            set { _Overwrite = value; }
        }
        /// <summary>
        /// 파일명을 임의로 변경합니다.
        /// </summary>
        public bool AutoRename
        {
            set { _AutoRename = value; }
            get { return _AutoRename; }
        }
        /// <summary>
        /// 서버의 물리적 저장 경로를 가져옵니다.
        /// </summary>
        public string PysicalPath
        {
            get { return _PhysicalPath; }
        }

        /// <summary>
        /// 저장된 이미지의 가로 크기를 가져옵니다.
        /// </summary>
        public int ImageWidth
        {
            get { return _ImageWidth; }
        }

        /// <summary>
        /// 저장된 이미지의 세로 크기를 가져옵니다.
        /// </summary>
        public int ImageHeight
        {
            get { return _ImageHeight; }
        }

        /// <summary>
        /// 파일의 컨텐츠 타입을 가져옵니다.
        /// </summary>
        public string MimeType
        {
            get { return _MimeType; }
        }

        #endregion

        #region /// 생성자

        /// <summary>
        /// 기본 생성자
        /// </summary>
        public FileUploadHelper()
        {
            Initialize();
        }

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="hpfUpFile">업로드할 파일입니다.</param>
        public FileUploadHelper(HttpPostedFile hpfUpFile)
        {
            Initialize();
            if (hpfUpFile == null)
                return;
            _PostedFile = hpfUpFile;
            _MimeType = _PostedFile.ContentType;
        }

        /// <summary>
        /// 변수 초기화
        /// </summary>
        private void Initialize()
        {
            _FileServer = Init.FileServer;
            _FileSize = 0;
            _LimitFileSize = 0;
            _AutoRename = true;
            _Overwrite = false;
            _NewFileName = "";
        }

        #endregion;

        #region /// public void Save()
        /// <summary>
        /// 파일 저장
        /// </summary>
        public void Save()
        {
            if (_PostedFile == null)
                throw new ApplicationException("저장할 파일이 설정되지 않았습니다.");
            if (_PostedFile.FileName == "")
                return;

            if (_VirtualPath == "")
                throw new ArgumentException("파일 저장 경로가 설정되지 않았습니다.");

            if (_VirtualPath.Substring(0, 1) != "/")
                _VirtualPath = "/" + _VirtualPath;
            if (_VirtualPath.Substring(_VirtualPath.Length - 1) != "/")
                _VirtualPath += "/";

            string strFullPath = _FileServer.VirtualPath + _VirtualPath;
            _PhysicalPath = Server.MapPath(strFullPath);

            // 업로드 폴더가 없으면 새로 생성.
            DirectoryInfo di = new DirectoryInfo(_PhysicalPath);
            if (!di.Exists)
                di.Create();

            // 끝에 \ 붙이기
            if (_PhysicalPath.Substring(_PhysicalPath.Length - 1) != @"\")
                _PhysicalPath += @"\";

            _FileName = _PostedFile.FileName;
            // 확장자 없으면 파일 업로드 금지
            if (_FileName.LastIndexOf(".") == -1)
                throw new ApplicationException("파일명에 확장자가 존재하지 않습니다.");

            #region /// 파일 리네임

            // 파일 리네임
            string strSaveFileName;
            if (_NewFileName == "")
            {
                strSaveFileName = _AutoRename ? DateTime.Now.ToString("yyyyMMddHHmmss") : Path.GetFileNameWithoutExtension(_FileName);
                // 확장자 저장
                _FileExtName = Path.GetExtension(_FileName);
            }
            else
            {
                strSaveFileName = Path.GetFileNameWithoutExtension(_NewFileName);
                // 확장자 저장
                _FileExtName = Path.GetExtension(_NewFileName);
            }

            // 파일 헤더
            if (_FilePrefix != "")
                strSaveFileName = _FilePrefix + "_" + strSaveFileName;

            int i = 0;
            FileInfo fiFileInfo;
            string tmpName;

            if (_Overwrite)
            {
                tmpName = strSaveFileName + _FileExtName;

                fiFileInfo = new FileInfo(_PhysicalPath + tmpName);
                if (fiFileInfo.Exists)
                    fiFileInfo.Delete();
            }
            else
            {
                // 파일명 중복 회피
                do
                {
                    tmpName = strSaveFileName + ((i > 0) ? "(" + i + ")" : "") + _FileExtName;
                    fiFileInfo = new FileInfo(_PhysicalPath + tmpName);
                    i++;
                } while (fiFileInfo.Exists);
            }

            #endregion

            #region	/// 파일 업로드 제한

            // 허용된 확장자 아니면 업로드 금지
            if (_RestrictExtention != "")
                if (Regex.IsMatch(_FileName, @"^\.?(?:" + _RestrictExtention + ")$"))
                    throw new ApplicationException("업로드를 허용하지 않는 파일입니다.");

            // 파일크기 Zero의 경우 업로드 금지
            _FileSize = _PostedFile.ContentLength;
            if (_FileSize <= 0)
                throw new ApplicationException("업로드 파일의 크기가 너무 작습니다.");

            // 용량 초과시 업로드 금지
            if (_LimitFileSize > 0)
                if (_FileSize > _LimitFileSize)
                    throw new ApplicationException("업로드 용량을 초과했습니다.");

            #endregion

            try
            {
                // 저장.
                _PostedFile.SaveAs(_PhysicalPath + tmpName);
            }
            catch (IOException e)
            {
                throw e;
            }

            if (_MimeType.IndexOf("image") != -1)
            {
                Image upImage = Image.FromFile(_PhysicalPath + tmpName);
                _ImageWidth = upImage.Width;
                _ImageHeight = upImage.Height;
            }

            // 파일이름 + 확장자
            _LastSavedFileName = tmpName;
            // 가상 경로 + 파일명 + 확장자
            _SavedPathName = _VirtualPath + tmpName;
            // 서버명 + 경로 + 파일명 + 확장자
            _URL = _FileServer.Url + _SavedPathName;
        }

        #endregion

        #region public void SaveAs(string newFileName)

        /// <summary>
        /// 다른 이름으로 파일 저장
        /// </summary>
        /// <param name="NewFileName">새로 지정할 파일명</param>
        public void SaveAs(string newFileName)
        {
            if (newFileName == null)
                throw new ArgumentNullException("저장할 파일명이 없습니다.");

            _NewFileName = newFileName;
            Save();
        }

        #endregion
    }
}
